-------------------------------------------------
-- mpris based Arc Widget for Awesome Window Manager
-- Modelled after Pavel Makhov's work
-- @author Mohammed Gaber
-- requires - playerctl
-- @copyright 2020
-------------------------------------------------
local awful = require("awful")
local beautiful = require("beautiful")
local watch = require("awful.widget.watch")
local wibox = require("wibox")
local gears = require("gears")

local GET_MPD_CMD = "playerctl -p %s -f '{{status}};{{xesam:artist}};{{xesam:title}}' metadata"

local TOGGLE_MPD_CMD = "playerctl play-pause"
local NEXT_MPD_CMD = "playerctl next"
local PREV_MPD_CMD = "playerctl previous"
local LIST_PLAYERS_CMD = "playerctl -l"

local PATH_TO_ICONS = "/usr/share/icons/Arc"
local PAUSE_ICON_NAME = PATH_TO_ICONS .. "/actions/24/player_pause.png"
local PLAY_ICON_NAME = PATH_TO_ICONS .. "/actions/24/player_play.png"
local STOP_ICON_NAME = PATH_TO_ICONS .. "/actions/24/player_stop.png"
local LIBRARY_ICON_NAME = PATH_TO_ICONS .. "/actions/24/music-library.png"

local default_player = ""

local icon = wibox.widget({
	id = "icon",
	widget = wibox.widget.imagebox,
	image = PLAY_ICON_NAME,
})

local artist_widget = wibox.widget({
	id = "artist",
	widget = wibox.widget.textbox,
})

local title_widget = wibox.widget({
	id = "title",
	widget = wibox.widget.textbox,
})

local mpris_widget = wibox.widget({
	artist_widget,
	{
		icon,
		max_value = 1,
		value = 0,
		thickness = 2,
		start_angle = 4.71238898, -- 2pi*3/4
		forced_height = 24,
		forced_width = 24,
		rounded_edge = true,
		bg = "#ffffff11",
		paddings = 0,
		widget = wibox.container.arcchart,
	},
	title_widget,
	layout = wibox.layout.fixed.horizontal,
})

local rows = { layout = wibox.layout.fixed.vertical }

local popup = awful.popup({
	bg = beautiful.bg_normal,
	ontop = true,
	visible = false,
	shape = gears.shape.rounded_rect,
	border_width = 1,
	border_color = beautiful.bg_focus,
	maximum_width = 400,
	offset = { y = 5 },
	widget = {},
})

local function rebuild_popup()
	awful.spawn.easy_async(LIST_PLAYERS_CMD, function(stdout, _, _, _)
		for i = 0, #rows do
			rows[i] = nil
		end
		for player_name in stdout:gmatch("[^\r\n]+") do
			if player_name ~= "" and player_name ~= nil then
				local checkbox = wibox.widget({
					{
						checked = player_name == default_player,
						color = beautiful.bg_normal,
						paddings = 2,
						shape = gears.shape.circle,
						forced_width = 20,
						forced_height = 20,
						check_color = beautiful.fg_urgent,
						widget = wibox.widget.checkbox,
					},
					valign = "center",
					layout = wibox.container.place,
				})

				checkbox:connect_signal("button::press", function()
					default_player = player_name
					rebuild_popup()
				end)

				table.insert(
					rows,
					wibox.widget({
						{
							{
								checkbox,
								{
									{
										text = player_name,
										align = "left",
										widget = wibox.widget.textbox,
									},
									left = 10,
									layout = wibox.container.margin,
								},
								spacing = 8,
								layout = wibox.layout.align.horizontal,
							},
							margins = 4,
							layout = wibox.container.margin,
						},
						bg = beautiful.bg_normal,
						widget = wibox.container.background,
					})
				)
			end
		end
	end)

	popup:setup(rows)
end

local function worker()
	-- retrieve song info
	local current_song, artist, player_status

	local update_graphic = function(widget, stdout, _, _, _)
		local words = gears.string.split(stdout, ";")
		player_status = words[1]
		artist = words[2]
		current_song = words[3]
		if current_song ~= nil then
			if string.len(current_song) > 30 then
				current_song = string.sub(current_song, 0, 9) .. ".."
			end
		end

		if player_status == "Playing" then
			icon.image = PLAY_ICON_NAME
			widget.colors = { beautiful.green }
			artist_widget.markup = "<span foreground='" .. beautiful.green .. "'>" .. artist .. "</span>"
			title_widget.markup = "<span foreground='" .. beautiful.green .. "'>" .. current_song .. "</span>"
		elseif player_status == "Paused" then
			icon.image = PAUSE_ICON_NAME
			widget.colors = { beautiful.red }
			artist_widget.markup = "<span foreground='" .. beautiful.red .. "'>" .. artist .. "</span>"
			title_widget.markup = "<span foreground='" .. beautiful.red .. "'>" .. current_song .. "</span>"
		elseif player_status == "Stopped" then
			icon.image = STOP_ICON_NAME
		else -- no player is running
			icon.image = LIBRARY_ICON_NAME
			widget.colors = { beautiful.red }
		end
	end

	mpris_widget:buttons(awful.util.table.join(
		awful.button({}, 3, function()
			if popup.visible then
				popup.visible = not popup.visible
			else
				rebuild_popup()
				popup:move_next_to(mouse.current_widget_geometry)
			end
		end),
		awful.button({}, 5, function()
			awful.spawn(NEXT_MPD_CMD, false)
		end),
		awful.button({}, 4, function()
			awful.spawn(PREV_MPD_CMD, false)
		end),
		awful.button({}, 1, function()
			awful.spawn(TOGGLE_MPD_CMD, false)
		end)
	))

	watch(string.format(GET_MPD_CMD, "'" .. default_player .. "'"), 1, update_graphic, mpris_widget)

	return mpris_widget
end

return setmetatable(mpris_widget, {

	__call = function(_, ...)
		return worker(...)
	end,
})
